import logging
import os
import ast
from datetime import datetime, timedelta
from typing import Optional, List

import numpy as np
import pandas as pd
from PySide6.QtWidgets import QWidget, QSizePolicy, QApplication

from ui.components.base.widget import TgBaseWidget
from ui.components.buttons.button import TgButton
from ui.components.inputs.line_edit import TgLineEdit
from ui.components.inputs.combo_box import TgComboBox
from ui.components.layouts.vbox_layout import TgVBoxLayout
from ui.components.layouts.hbox_layout import TgHBoxLayout
from ui.components.composite.form_layout import TgFormLayout
from ui.components.composite.button_group import TgButtonGroup
from ui.components.dialogs.file_dialog import TgFileDialog
from ui.components.feedback.progress_bar import TgProgressBar
from ui.components.dialogs.message_box import TgMessageBox
from ui.components.composite.table import TgTable
from ui.components.composite.log_box import LogBox
from ui.components.charts.line_chart_echarts import TgLineChartEcharts
from ui.components.charts.bar_chart_echarts import TgBarChartEcharts

from .dialogs.backtest_history_dialog import BacktestHistoryDialog
from .dialogs.optimization_setting_dialog import OptimizationSettingDialog
from .dialogs.optimization_result_dialog import OptimizationResultDialog
from .dialogs.strategy_parameter_dialog import StrategyParameterDialog
from .dialogs.backtest_records_dialog import BacktestRecordsDialog

from ..controllers.single_variety_backtesting_controller import (
    SingleVarietyBacktestingController,
)
from ..models.single_variety_backtesting_model import (
    SingleVarietyBacktestingModel,
)


logger = logging.getLogger(__name__)


class SingleVarietyBacktestingView(TgBaseWidget):
    """单品种回测 View（MVC）：负责 UI 交互与展示。

    - 注释中文；日志英文
    """

    def __init__(self):
        super().__init__()
        # 控制器与模型
        self.controller = SingleVarietyBacktestingController()
        self.model = SingleVarietyBacktestingModel()

        # 运行态
        self.strategy_file_path: str = ""
        self.backtest_trades: List[dict] = []
        self.backtest_orders: List[dict] = []
        self.backtest_daily_results: List[dict] = []
        self.optimization_results: List[dict] = []
        self.is_optimizing: bool = False
        self.target_display_name: str = "优化目标"

        # 构建界面
        self._init_ui()
        # 加载本地代码
        self._load_local_codes()

    # ---------- UI ----------
    def _init_ui(self) -> None:
        layout = TgVBoxLayout(self)

        form_layout = TgFormLayout()
        # 行内输入框自适应扩展，但设置合理上限，避免撑出横向滚动条
        input_max_width = 800
        field_max_width = 800  # 下拉等控件保持较合理的最大宽度

        self.strategy_line_edit = TgLineEdit()
        self.strategy_line_edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.strategy_line_edit.setMaximumWidth(input_max_width)
        self.browse_button = TgButton("浏览", size="small")
        self.browse_button.clicked.connect(self.browse_strategy_file)
        # 使用内嵌水平布局让“浏览”按钮紧挨输入框显示
        strategy_row_container = QWidget()
        strategy_row_layout = TgHBoxLayout(strategy_row_container, margins='none', spacing='sm')
        strategy_row_layout.addWidget(self.strategy_line_edit, 1)
        strategy_row_layout.addWidget(self.browse_button)
        form_layout.add_row("交易策略:", strategy_row_container)

        self.local_code_combo = TgComboBox()
        self.local_code_combo.setMaximumWidth(field_max_width)
        self.local_code_combo.currentTextChanged.connect(self.update_contract_multiplier)
        form_layout.add_row("本地代码:", self.local_code_combo)

        self.contract_type_combo = TgComboBox()
        self.contract_type_combo.setMaximumWidth(field_max_width)
        self.contract_type_combo.addItems(["指数连续(99)", "主力连续(888)"])
        form_layout.add_row("合约类型:", self.contract_type_combo)

        self.kline_period_combo = TgComboBox()
        self.kline_period_combo.setMaximumWidth(field_max_width)
        self.kline_period_combo.addItems(["1m", "d"])
        form_layout.add_row("K线周期:", self.kline_period_combo)

        end_date = datetime.now()
        start_date = end_date - timedelta(days=3*365)
        self.start_date_edit = TgLineEdit(placeholder_text="YYYY/MM/DD")
        self.start_date_edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.start_date_edit.setMaximumWidth(input_max_width)
        self.start_date_edit.setText(start_date.strftime("%Y/%m/%d"))
        self.end_date_edit = TgLineEdit(placeholder_text="YYYY/MM/DD")
        self.end_date_edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.end_date_edit.setMaximumWidth(input_max_width)
        self.end_date_edit.setText(end_date.strftime("%Y/%m/%d"))
        self.fee_rate_edit = TgLineEdit(placeholder_text="例如: 0.0001")
        self.fee_rate_edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.fee_rate_edit.setMaximumWidth(input_max_width)
        self.fee_rate_edit.setText("0.0001")
        self.slippage_edit = TgLineEdit(placeholder_text="总滑点 = 交易手数 * 合约乘数 * 滑点比例， 默认0")
        self.slippage_edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.slippage_edit.setMaximumWidth(input_max_width)
        self.slippage_edit.setText("0")
        self.multiplier_edit = TgLineEdit()
        self.multiplier_edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.multiplier_edit.setMaximumWidth(input_max_width)
        self.price_tick_edit = TgLineEdit(placeholder_text="请自行查询合约信息, 默认0.1")
        self.price_tick_edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.price_tick_edit.setMaximumWidth(input_max_width)
        self.price_tick_edit.setText("0.1")
        self.capital_edit = TgLineEdit(placeholder_text="例如: 1000000")
        self.capital_edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.capital_edit.setMaximumWidth(input_max_width)
        self.capital_edit.setText("1000000")

        form_layout.add_row("开始日期:", self.start_date_edit)
        form_layout.add_row("结束日期:", self.end_date_edit)
        form_layout.add_row("手续费率:", self.fee_rate_edit)
        form_layout.add_row("交易滑点:", self.slippage_edit)
        form_layout.add_row("合约乘数:", self.multiplier_edit)
        form_layout.add_row("价格跳动:", self.price_tick_edit)
        form_layout.add_row("回测资金:", self.capital_edit)

        # 创建回测按钮组
        backtest_button_configs = [
            {"text": "开始回测", "theme": "primary", "callback": self.run_backtest},
            {"text": "查看历史", "theme": "secondary", "callback": self.show_history},
            {"text": "成交记录", "theme": "secondary", "callback": self.show_backtesting_trades},
            {"text": "委托记录", "theme": "secondary", "callback": self.show_backtesting_orders},
            {"text": "每日盈亏", "theme": "secondary", "callback": self.show_daily_results},
        ]
        self.backtest_button_group = TgButtonGroup(backtest_button_configs)
        
        # 创建优化按钮组
        optimization_button_configs = [
            {"text": "参数优化", "theme": "primary", "callback": self.run_optimization},
            {"text": "优化结果", "theme": "secondary", "callback": self.show_optimization_results},
        ]
        self.optimization_button_group = TgButtonGroup(optimization_button_configs)

        # 初始禁用部分按钮
        self.optimization_result_button = None
        self.trade_button_ref = None
        self.order_button_ref = None
        self.daily_button_ref = None
        
        # 回测组按钮引用
        for button_text, button in self.backtest_button_group.buttons.items():
            if button_text == "成交记录":
                self.trade_button_ref = button
                button.setEnabled(False)
            elif button_text == "委托记录":
                self.order_button_ref = button
                button.setEnabled(False)
            elif button_text == "每日盈亏":
                self.daily_button_ref = button
                button.setEnabled(False)
        
        # 优化组按钮引用
        for button_text, button in self.optimization_button_group.buttons.items():
            if button_text == "优化结果":
                self.optimization_result_button = button
                button.setEnabled(False)

        form_layout.add_row("回测操作:", self.backtest_button_group)
        form_layout.add_row("优化操作:", self.optimization_button_group)

        layout.addWidget(form_layout)

        # 日志显示
        self.log_box = LogBox(placeholder_text="回测日志将在此处显示...")
        layout.addWidget(self.log_box)

        # 结果图表
        self.balance_plot = TgLineChartEcharts(title="账户净值")
        self.drawdown_plot = TgLineChartEcharts(title="回撤")
        self.daily_pnl_plot = TgBarChartEcharts(title="每日盈亏")
        self.pnl_distribution_plot = TgBarChartEcharts(title="盈亏分布")
        self.statistics_table = TgTable(editable=False, font_size='small', highlight_on_selection=False)

        # 图表固定高度
        self.balance_plot.setFixedHeight(300)
        self.drawdown_plot.setFixedHeight(300)
        self.daily_pnl_plot.setFixedHeight(300)
        self.pnl_distribution_plot.setFixedHeight(300)

        layout.addWidget(self.balance_plot)
        layout.addWidget(self.drawdown_plot)
        layout.addWidget(self.daily_pnl_plot)
        layout.addWidget(self.pnl_distribution_plot)
        layout.addWidget(self.statistics_table)

        # 初始隐藏
        self.balance_plot.hide()
        self.drawdown_plot.hide()
        self.daily_pnl_plot.hide()
        self.pnl_distribution_plot.hide()
        self.statistics_table.hide()

    # ---------- 业务交互 ----------
    def _load_local_codes(self) -> None:
        try:
            codes = self.controller.load_local_codes()
            if codes:
                self.local_code_combo.addItems(codes)
        except Exception as e:
            logger.exception(e)
            TgMessageBox.warning(self, "加载失败", f"加载本地代码时发生错误: {e}\n\n请检查数据库连接或在'设置'选项卡中导入合约信息。")

    def update_contract_multiplier(self, text: str) -> None:
        if not text:
            return
        try:
            multiplier = self.controller.fetch_multiplier(text)
            if multiplier is not None:
                self.multiplier_edit.setText(str(multiplier))
            else:
                logger.warning(f"Contract multiplier not found for {text}")
        except Exception as e:
            logger.exception(e)
            TgMessageBox.warning(self, "加载失败", f"加载合约乘数时发生错误: {e}\n\n请检查合约信息是否正确导入。")

    def _build_params_from_inputs(self) -> Optional[dict]:
        """从表单构建参数，失败时弹窗并返回 None。"""
        try:
            return self.model.build_params(
                strategy_name=self.strategy_line_edit.text(),
                strategy_file_path=self.strategy_file_path,
                local_code=self.local_code_combo.currentText(),
                contract_type_text=self.contract_type_combo.currentText(),
                kline_period=self.kline_period_combo.currentText(),
                start_date_str=self.start_date_edit.text(),
                end_date_str=self.end_date_edit.text(),
                fee_rate_str=self.fee_rate_edit.text(),
                slippage_str=self.slippage_edit.text(),
                multiplier_str=self.multiplier_edit.text(),
                price_tick_str=self.price_tick_edit.text(),
                capital_str=self.capital_edit.text(),
            )
        except Exception as e:
            logger.exception(e)
            TgMessageBox.warning(self, "参数错误", f"{e}")
            return None

    def run_backtest(self) -> None:
        """启动回测。"""
        params = self._build_params_from_inputs()
        if not params:
            return

        # 需要策略文件以便读取策略默认参数
        if not self.strategy_file_path:
            TgMessageBox.warning(self, "策略文件缺失", "请先选择策略文件。")
            return

        # 弹出参数编辑对话框，允许用户修改策略参数
        try:
            strategy_params = self.controller.get_strategy_default_parameters(
                self.strategy_file_path, params["strategy_name"]
            )
            if strategy_params:
                dialog = StrategyParameterDialog(params["strategy_name"], strategy_params, self)
                if dialog.exec() != dialog.DialogCode.Accepted:
                    return
                user_setting = dialog.get_setting()
                # 合并用户设置到回测参数（作为策略特定参数传递）
                params.update(user_setting)
            else:
                self.log_box.append("该策略未提供可配置参数，使用默认参数进行回测。")
        except Exception as e:
            logger.exception(e)
            TgMessageBox.warning(self, "参数错误", f"获取或设置策略参数时发生错误：\n{e}")
            return

        # 清空日志显示并开始
        self.log_box.clear()
        self.log_box.append("开始回测...")

        try:
            backtest_result = self.controller.run_backtest(params, self.log_box.log)
            # 尽量展开返回内容（兼容不同返回长度）
            success = False
            message = ""
            results = None
            statistics = None
            history_data = None
            trades_list: List[dict] = []
            orders_list: List[dict] = []
            daily_results_list: List[dict] = []

            (
                success,
                message,
                results,
                statistics,
                history_data,
                trades_list,
                orders_list,
                daily_results_list,
            ) = backtest_result[:8]

            self.backtest_trades = trades_list
            self.backtest_orders = orders_list
            self.backtest_daily_results = daily_results_list

            if success and results is not None and statistics is not None:
                self.log_box.append("回测完成！")
                self.display_backtest_results(results, statistics, history_data, params)
                if self.trade_button_ref:
                    self.trade_button_ref.setEnabled(True)
                if self.order_button_ref:
                    self.order_button_ref.setEnabled(True)
                if self.daily_button_ref:
                    self.daily_button_ref.setEnabled(True)

                # 保存回测结果
                self.log_box.append("正在保存回测结果到数据库...")
                try:
                    result_id = self.controller.save_backtest_result(params, statistics, results)
                    if result_id:
                        self.log_box.append(f"✓ 回测结果已保存到数据库，ID: {result_id}")
                        logger.info(f"Backtest saved with id: {result_id}")
                    else:
                        self.log_box.append("✗ 保存回测结果到数据库失败")
                        logger.warning("Failed to save backtest result")
                except Exception as save_error:
                    self.log_box.append(f"✗ 保存回测结果时发生错误: {save_error}")
                    logger.exception(save_error)
                    TgMessageBox.warning(
                        self,
                        "保存失败",
                        f"保存回测结果到数据库时发生错误：\n{save_error}\n\n请检查数据库连接或联系技术支持。",
                    )
            else:
                self.log_box.append(f"回测失败: {message}")
                detailed_message = message or "回测失败"
                if "未产生任何交易记录" in detailed_message:
                    detailed_message += "\n\n建议检查：\n1. 数据时间范围是否正确\n2. 策略参数是否合理\n3. 合约代码是否存在对应数据"
                elif "回测结果为空" in detailed_message:
                    detailed_message += "\n\n建议检查：\n1. 选择的时间范围内是否有数据\n2. 合约代码格式是否正确\n3. 策略逻辑是否正常"
                elif "策略文件导入失败" in detailed_message:
                    detailed_message += "\n\n建议检查：\n1. 策略文件路径是否正确\n2. 策略文件语法是否正确\n3. 是否缺少必要的导入"
                elif "策略类" in detailed_message and "未找到" in detailed_message:
                    detailed_message += "\n\n建议检查：\n1. 策略类名是否正确\n2. 策略类是否继承了正确的基类\n3. 文件中是否确实包含该策略类"
                TgMessageBox.warning(self, "回测失败", detailed_message)
        except Exception as e:
            self.log_box.append(f"回测过程中发生意外错误：{e}")
            logger.exception(e)
            TgMessageBox.critical(self, "系统错误", f"回测过程中发生意外错误：{e}\n\n请检查日志文件获取详细信息。")

    def run_optimization(self) -> None:
        """启动参数优化。"""
        if self.is_optimizing:
            TgMessageBox.warning(self, "正在优化", "参数优化正在进行中，请等待完成。")
            return

        params = self._build_params_from_inputs()
        if not params:
            return

        if not self.strategy_file_path:
            TgMessageBox.warning(self, "策略文件缺失", "请先选择策略文件。")
            return

        try:
            strategy_params = self.controller.get_strategy_default_parameters(
                self.strategy_file_path, params["strategy_name"]
            )
            if not strategy_params:
                TgMessageBox.information(
                    self,
                    "无可优化参数",
                    "该策略没有可优化的参数，或无法获取策略参数。\n\n请确保策略类定义了parameters属性或构造函数参数。",
                )
                return

            # 显示优化设置对话框
            dialog = OptimizationSettingDialog(params["strategy_name"], strategy_params, self)
            if dialog.exec() == dialog.DialogCode.Accepted:
                optimization_setting, use_ga, max_workers, target_display_name = dialog.get_setting()
                if optimization_setting:
                    self.target_display_name = target_display_name
                    self._start_optimization(params, optimization_setting, use_ga, max_workers)
        except Exception as e:
            logger.exception(e)
            TgMessageBox.warning(self, "优化失败", f"启动参数优化时发生错误:\n{e}")

    def _start_optimization(self, backtest_params: dict, optimization_setting: dict, use_ga: bool, max_workers: int) -> None:
        """启动优化线程（通过控制器）。"""
        self.is_optimizing = True
        self.optimization_results = []
        self._set_optimization_ui_state(False)
        self.log_box.clear()
        self.log_box.append("开始参数优化...")

        self.controller.start_optimization(
            backtest_params,
            optimization_setting,
            use_ga,
            max_workers,
            on_progress=self._on_optimization_progress,
            on_finished=self._on_optimization_finished,
            on_error=self._on_optimization_error,
        )

    def _set_optimization_ui_state(self, enabled: bool) -> None:
        # 禁用/启用回测按钮组中的开始回测按钮
        for button_text, button in self.backtest_button_group.buttons.items():
            if button_text == "开始回测":
                button.setEnabled(enabled)
        
        # 禁用/启用优化按钮组中的参数优化按钮
        for button_text, button in self.optimization_button_group.buttons.items():
            if button_text == "参数优化":
                button.setEnabled(enabled)

    def _on_optimization_progress(self, current: int, total: int, message: str) -> None:
        self.log_box.append(f"[{current}/{total}] {message}")
        QApplication.processEvents()

    def _on_optimization_finished(self, results: list) -> None:
        self.is_optimizing = False
        self.optimization_results = results
        self._set_optimization_ui_state(True)
        if self.optimization_result_button:
            self.optimization_result_button.setEnabled(True)
        self.log_box.append(f"参数优化完成！找到 {len(results)} 个结果。")
        self.log_box.append("点击'优化结果'按钮查看详细结果。")
        logger.info(f"Parameter optimization completed with {len(results)} results")

    def _on_optimization_error(self, error_message: str) -> None:
        self.is_optimizing = False
        self._set_optimization_ui_state(True)
        self.log_box.append(f"参数优化失败: {error_message}")
        TgMessageBox.warning(self, "优化失败", f"参数优化过程中发生错误:\n{error_message}")
        logger.warning(f"Parameter optimization failed: {error_message}")

    def show_optimization_results(self) -> None:
        if not self.optimization_results:
            TgMessageBox.information(self, "无结果", "暂无优化结果可显示。\n\n请先运行参数优化。")
            return
        try:
            dialog = OptimizationResultDialog(self.optimization_results, self.target_display_name, self)
            dialog.exec()
        except Exception as e:
            logger.exception(e)
            TgMessageBox.warning(self, "显示失败", f"显示优化结果时发生错误:\n{e}")

    # ---------- 历史/记录 ----------
    def show_history(self) -> None:
        try:
            dialog = BacktestHistoryDialog(self)
            dialog.exec()
        except Exception as e:
            logger.exception(e)
            TgMessageBox.warning(self, "显示历史记录失败", f"显示历史记录时发生错误: {e}")

    def show_backtesting_trades(self) -> None:
        trades_data = getattr(self, 'backtest_trades', None)
        if not trades_data or len(trades_data) == 0:
            TgMessageBox.information(self, "暂无数据", "请先运行回测，或没有产生成交记录。")
            return
        columns = [
            {"key": "tradeid", "title": "成交号"},
            {"key": "orderid", "title": "委托号"},
            {"key": "symbol", "title": "合约"},
            {"key": "exchange", "title": "交易所"},
            {"key": "direction", "title": "方向"},
            {"key": "offset", "title": "开平"},
            {"key": "price", "title": "价格"},
            {"key": "volume", "title": "数量"},
            {"key": "datetime", "title": "时间"},
            {"key": "gateway_name", "title": "接口"},
        ]
        dlg = BacktestRecordsDialog("回测成交记录", columns, trades_data, self)
        dlg.exec()

    def show_backtesting_orders(self) -> None:
        orders_data = getattr(self, 'backtest_orders', None)
        if not orders_data or len(orders_data) == 0:
            TgMessageBox.information(self, "暂无数据", "请先运行回测，或没有产生委托记录。")
            return
        columns = [
            {"key": "orderid", "title": "委托号"},
            {"key": "symbol", "title": "合约"},
            {"key": "exchange", "title": "交易所"},
            {"key": "type", "title": "类型"},
            {"key": "direction", "title": "方向"},
            {"key": "offset", "title": "开平"},
            {"key": "price", "title": "价格"},
            {"key": "volume", "title": "总数量"},
            {"key": "traded", "title": "已成交"},
            {"key": "status", "title": "状态"},
            {"key": "datetime", "title": "时间"},
            {"key": "gateway_name", "title": "接口"},
        ]
        dlg = BacktestRecordsDialog("回测委托记录", columns, orders_data, self)
        dlg.exec()

    def show_daily_results(self) -> None:
        daily_data = getattr(self, 'backtest_daily_results', None)
        if not daily_data or len(daily_data) == 0:
            TgMessageBox.information(self, "暂无数据", "请先运行回测，或没有产生每日盈亏明细。")
            return
        columns = [
            {"key": "date", "title": "日期"},
            {"key": "trade_count", "title": "成交笔数"},
            {"key": "start_pos", "title": "起始持仓"},
            {"key": "end_pos", "title": "收盘持仓"},
            {"key": "turnover", "title": "成交额"},
            {"key": "commission", "title": "手续费"},
            {"key": "slippage", "title": "滑点"},
            {"key": "trading_pnl", "title": "交易盈亏"},
            {"key": "holding_pnl", "title": "持仓盈亏"},
            {"key": "total_pnl", "title": "总盈亏"},
            {"key": "net_pnl", "title": "净盈亏"},
        ]
        dlg = BacktestRecordsDialog("回测每日盈亏", columns, daily_data, self)
        dlg.exec()

    # ---------- 文件/参数 ----------
    def browse_strategy_file(self) -> None:
        dialog = TgFileDialog(self)
        file_path = dialog.get_open_file_name(title="选择策略文件", extensions=["py"])
        if file_path:
            self.strategy_file_path = file_path
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                if not content.strip():
                    TgMessageBox.warning(self, "文件为空", "选择的策略文件为空，请选择有效的策略文件。")
                    return
                tree = ast.parse(content)
                strategy_classes: List[str] = []
                for node in ast.walk(tree):
                    if isinstance(node, ast.ClassDef):
                        for base in node.bases:
                            if isinstance(base, ast.Name):
                                strategy_classes.append(node.name)
                if strategy_classes:
                    self.strategy_line_edit.setText(strategy_classes[0])
                    if len(strategy_classes) > 1:
                        TgMessageBox.information(self, "多个策略类", f"文件中找到多个策略类：{', '.join(strategy_classes)}\n已自动选择：{strategy_classes[0]}")
                else:
                    TgMessageBox.warning(self, "未找到策略类", "文件中未找到合适的策略类。\n\n请确保策略类继承了正确的基类（如 CtaTemplate）。")
            except SyntaxError as se:
                logger.exception(se)
                TgMessageBox.warning(self, "语法错误", f"策略文件存在语法错误：{se}\n\n请检查文件语法是否正确。")
            except UnicodeDecodeError as ude:
                logger.exception(ude)
                TgMessageBox.warning(self, "编码错误", f"策略文件编码错误：{ude}\n\n请确保文件使用UTF-8编码。")
            except FileNotFoundError:
                TgMessageBox.warning(self, "文件未找到", "选择的策略文件不存在，请重新选择。")
            except Exception as e:
                logger.exception(e)
                TgMessageBox.warning(self, "解析失败", f"解析策略文件时发生错误: {e}\n\n请检查文件是否为有效的Python策略文件。")

    # ---------- 结果展示 ----------
    def display_backtest_results(self, results: pd.DataFrame, statistics: dict, history_data=None, params=None) -> None:
        """显示回测结果。"""
        # 净值曲线
        self.balance_plot.clear()
        if results.index.dtype == 'object':
            results.index = pd.to_datetime(results.index)
        daily_results = results.resample('D').last().dropna()

        self.balance_plot.set_data(
            df=daily_results,
            x_column=daily_results.index.tolist(),
            y_column=daily_results['balance'].tolist(),
            name="账户净值",
            color='#1f77b4',
        )

        underlying_dd_x = None
        underlying_dd_y = None
        if history_data is not None and len(history_data) > 0 and params is not None:
            try:
                if isinstance(history_data, list):
                    history_df = pd.DataFrame([
                        {'datetime': bar.datetime, 'close_price': bar.close_price}
                        for bar in history_data
                    ])
                    history_df.set_index('datetime', inplace=True)
                elif hasattr(history_data, 'close_price'):
                    history_df = pd.DataFrame([
                        {'datetime': history_data.datetime, 'close_price': history_data.close_price}
                    ])
                    history_df.set_index('datetime', inplace=True)
                else:
                    history_df = history_data.copy()

                if not history_df.empty and 'close_price' in history_df.columns:
                    daily_history = history_df.resample('D').last().dropna()

                    try:
                        if getattr(daily_history.index, 'tz', None) is not None:
                            daily_history.index = daily_history.index.tz_convert('Asia/Shanghai').tz_localize(None)
                        if getattr(daily_results.index, 'tz', None) is not None:
                            daily_results.index = daily_results.index.tz_convert('Asia/Shanghai').tz_localize(None)
                    except Exception as e:
                        logger.exception(e)

                    start_date = daily_results.index.min()
                    end_date = daily_results.index.max()
                    daily_history = daily_history[(daily_history.index >= start_date) & (daily_history.index <= end_date)]

                    if not daily_history.empty:
                        initial_capital = params.get('capital', 1000000)
                        price_returns = daily_history['close_price'].pct_change().fillna(0)
                        cumulative_asset_value = initial_capital * (1 + price_returns).cumprod()
                        self.balance_plot.add_series(
                            x_data=list(cumulative_asset_value.index),
                            y_data=cumulative_asset_value.tolist(),
                            name="标的累计收益",
                            color='#ff7f0e',
                        )
                        try:
                            cum_max = cumulative_asset_value.cummax()
                            dd_series = ((cumulative_asset_value / cum_max) - 1.0) * 100
                            underlying_dd_x = list(dd_series.index)
                            underlying_dd_y = dd_series.tolist()
                        except Exception as e:
                            logger.exception(e)
                        self.balance_plot.update_chart()
            except Exception as e:
                logger.exception(e)
                logger.warning(f"Failed to calculate underlying asset returns: {e}")

        # 回撤曲线
        self.drawdown_plot.clear()
        self.drawdown_plot.set_data(
            df=daily_results,
            x_column=daily_results.index.tolist(),
            y_column=daily_results['ddpercent'].tolist(),
            name="回撤百分比",
            color='#ff7f0e',
        )
        if underlying_dd_x is not None and underlying_dd_y is not None:
            try:
                self.drawdown_plot.add_series(
                    x_data=underlying_dd_x,
                    y_data=underlying_dd_y,
                    name="标的回撤",
                    color='#1f77b4',
                )
                self.drawdown_plot.update_chart()
            except Exception as e:
                logger.exception(e)

        # 每日盈亏柱状图
        self.daily_pnl_plot.clear()
        daily_pnl = daily_results['net_pnl'].diff().fillna(0)
        bar_colors = ['#d62728' if pnl < 0 else '#2ca02c' for pnl in daily_pnl]
        self.daily_pnl_plot.set_data(
            df=daily_results,
            x_column=daily_results.index.tolist(),
            y_column=daily_pnl.tolist(),
            name="每日盈亏",
            colors=bar_colors,
        )

        # 盈亏分布直方图
        self.pnl_distribution_plot.clear()
        non_zero_pnl = daily_pnl[daily_pnl != 0]
        if non_zero_pnl.size > 0:
            hist, bin_edges = np.histogram(non_zero_pnl, bins=50)
            bin_labels = [f"{bin_edges[i]:.2f}-{bin_edges[i+1]:.2f}" for i in range(len(bin_edges)-1)]
            self.pnl_distribution_plot.set_data(
                df=pd.DataFrame({'bins': bin_labels, 'counts': hist}),
                x_column=bin_labels,
                y_column=hist.tolist(),
                name="频次",
                colors=None,
            )

        # 统计表
        headers = ["指标", "数值"]
        statistics_translation = {
            "start_date": "开始日期",
            "end_date": "结束日期",
            "total_days": "总天数",
            "profit_days": "盈利天数",
            "loss_days": "亏损天数",
            "capital": "起始资金",
            "end_balance": "结束资金",
            "max_drawdown": "最大回撤",
            "max_ddpercent": "最大回撤百分比",
            "max_drawdown_duration": "最大回撤持续天数",
            "total_net_pnl": "总盈亏",
            "daily_net_pnl": "日均盈亏",
            "total_commission": "总手续费",
            "daily_commission": "日均手续费",
            "total_slippage": "总滑点",
            "daily_slippage": "日均滑点",
            "total_turnover": "总成交额",
            "daily_turnover": "日均成交额",
            "total_trade_count": "总成交笔数",
            "daily_trade_count": "日均成交笔数",
            "total_return": "总收益率",
            "annual_return": "年化收益率",
            "daily_return": "日均收益率",
            "win_rate": "胜率",
            "sharpe_ratio": "夏普比率",
            "ewm_sharpe": "EWM夏普比率",
            "return_std": "收益标准差",
            "return_drawdown_ratio": "收益回撤比",
        }
        ordered_keys = [
            "start_date", "end_date", "total_days",
            "capital", "end_balance",
            "total_net_pnl", "total_return", "annual_return",
            "max_drawdown", "max_ddpercent", "max_drawdown_duration",
            "sharpe_ratio", "return_drawdown_ratio", "win_rate",
            "total_trade_count", "daily_trade_count",
            "profit_days", "loss_days",
            "total_commission", "daily_commission",
            "total_slippage", "daily_slippage",
            "total_turnover", "daily_turnover",
            "daily_return", "return_std", "ewm_sharpe",
        ]
        data = []
        for key in ordered_keys:
            if key in statistics:
                value = statistics[key]
                display_key = statistics_translation.get(key, key)
                if isinstance(value, float):
                    data.append([display_key, f"{value:.2f}"])
                else:
                    data.append([display_key, str(value)])
        for key, value in statistics.items():
            if key not in ordered_keys:
                display_key = statistics_translation.get(key, key)
                if isinstance(value, float):
                    data.append([display_key, f"{value:.2f}"])
                else:
                    data.append([display_key, str(value)])
        self.statistics_table.set_data(headers, data)
        self.statistics_table.set_auto_height()

        # 显示所有结果部件
        self.balance_plot.show()
        self.drawdown_plot.show()
        self.daily_pnl_plot.show()
        self.pnl_distribution_plot.show()
        self.statistics_table.show()


# 保持旧名称兼容
SingleVarietyBacktestingTab = SingleVarietyBacktestingView


